package aufgabe_2_test.try01;

import static akka.actor.Actors.remote;

import java.math.BigInteger;
import java.util.Random;

import akka.actor.ActorRef;
import akka.actor.UntypedActor;
import akka.remoteinterface.RemoteServerModule;


public class MasterAndWorker extends  UntypedActor {
	
	private static BigInteger zero = BigInteger.ZERO;
	private static BigInteger one = BigInteger.ONE;
	private static BigInteger two = BigInteger.valueOf(2);
	private static BigInteger three = BigInteger.valueOf(3);
	private static Random rnd = new Random();
	
	static  RemoteServerModule remoteSupport; 

	@Override
	public void onReceive(Object ob) throws Exception {

		
		if(ob instanceof RhoRequest){
			RhoRequest req = (RhoRequest) ob;
			
			
			BigInteger tmpres = ((RhoRequest) ob).getN();
			for (int i = 0; tmpres.compareTo(new BigInteger("1"))> 0 ; i++) {
				RhoMessage res = PollardMethod( tmpres, req.getA() );
				System.out.println(res);
//				if(res.factorFound && res.factor.compareTo(new BigInteger("0"))>0 && (tmpres.mod(res.factor)).equals(new BigInteger("0")) && isPrime(res.factor) ){
//					System.out.println("zahl " + res.factor + " primzahl:" + isPrime(res.factor));
//					tmpres = tmpres.divide(res.factor);
////					System.out.println("gefunden:" + res.factor);
//				}
			}
		}else{
			
		}
		
	}
	
	


	public static RhoMessage PollardMethod(BigInteger n, BigInteger a){
		BigInteger x = nextRandomBigInteger(n,rnd);
		BigInteger y = new BigInteger(x.toByteArray()); 
		BigInteger p = BigInteger.ONE; 
		BigInteger d = BigInteger.ZERO;
		while(p.equals(one)){ 
			x = x.multiply(x).add(a).mod(n);//(x*x+ a) % n; 
			y = y.multiply(y).add(a).mod(n);//(y*y+ a) % n; 
			y = y.multiply(y).add(a).mod(n);//(y*y+ a) % n; 
			d = y.subtract(x).mod(n);		//(y  -  x) % n; 
			p = n.gcd(d);
		}
		return new RhoMessage(!p.equals(n), p);
	}

//	public static boolean isPrime(BigInteger bigi) {
//		BigInteger inc = new BigInteger("2");
//		BigInteger div = new BigInteger(bigi.toByteArray());
//		div = div.divide(inc);
//		for (BigInteger i = new BigInteger("2"); div.compareTo(i) >= 0; i=i.add(inc)) {
//			if (bigi.mod(i).equals(zero)) {
//				return false;
//			}
//		}
//		return true;
//	}
	
	public static BigInteger nextRandomBigInteger(BigInteger n,Random rand) {
	    BigInteger result = new BigInteger(n.bitLength(), rand);
	    while( result.compareTo(n) >= 0 ) {
	        result = new BigInteger(n.bitLength(), rand);
	    }
	    return result;
	}
	public static BigInteger sqrt(BigInteger n) {
		BigInteger a = BigInteger.ONE;
		BigInteger b = new BigInteger(n.shiftRight(5).add(BigInteger.valueOf(8)).toByteArray());
		while (b.compareTo(a) >= 0) {
			BigInteger mid = new BigInteger((a.add(b).shiftRight(1)).toByteArray());
			if (mid.multiply(mid).compareTo(n) > 0)
				b = mid.subtract(BigInteger.ONE);
			else
				a = mid.add(BigInteger.ONE);
		}
		return a.subtract(BigInteger.ONE);
	}

	public static boolean isPrime(BigInteger bigi) {
		BigInteger inc = two;
		BigInteger div = new BigInteger(bigi.toByteArray());
		if(div.mod(inc).equals(BigInteger.ZERO)){
			return false;
		}
		//use sqrt
		BigInteger sqrt = sqrt(bigi);
		for (BigInteger i = three; sqrt.compareTo(i) >= 0; i=i.add(inc)) {
			if (bigi.mod(i).equals(BigInteger.ZERO)) {
				return false;
			}
		}
		return true;
	}
	
	public  static  void main(String[] args) {
//		String s = "1000602106143806596478722974273666950903906112131794745457338659266842446985022076792112309173975243506969710503";
//		BigInteger m =new BigInteger(s);
//		System.out.println(s.length());
//		System.out.println(m.bitCount());
//		return;
//		BigInteger n = new BigInteger("60404042515723748783203728002475802385409495080659462440959668512216183250409555737");
//			BigInteger c = BigInteger.ONE;
//			BigInteger b = new BigInteger(n.shiftRight(5).add(BigInteger.valueOf(8)).toByteArray());
//			while (b.compareTo(c) >= 0) {
//				BigInteger mid = new BigInteger((c.add(b).shiftRight(1)).toByteArray());
//				if (mid.multiply(mid).compareTo(n) > 0)
//					b = mid.subtract(BigInteger.ONE);
//				else
//					c = mid.add(BigInteger.ONE);
//			}
//		System.out.println(c.subtract(BigInteger.ONE));
//
//		// next round 
//		System.out.println(isPrime(n));
//		
//		BigInteger a = BigInteger.valueOf(29093);
//		BigInteger x = nextRandomBigInteger(n,rnd);
//		BigInteger y = new BigInteger(x.toByteArray()); 
//		BigInteger p = BigInteger.ONE;
//		BigInteger d = BigInteger.ZERO;
//		long i = 0;
//		while(p.equals(BigInteger.ONE)){
//			x = x.multiply(x).add(a).mod(n);//(x*x+ a) % n; 
//			y = y.multiply(y).add(a).mod(n);//(y*y+ a) % n; 
//			y = y.multiply(y).add(a).mod(n);//(y*y+ a) % n; 
////			d = y.subtract(x).mod(n);		//(y  -  x) % n; 
////			p = n.gcd(d);
//			p = ((x.subtract(y)).abs()).gcd(n); 
//			i++;
//			if( i%1000000 == 0) System.out.println(i);
//		}
//		System.out.println("rdy");
//		
//		
//		BigInteger b = new BigInteger("3");
//		System.out.println(b.mod(new BigInteger("2")).equals(BigInteger.ZERO));
//		BigInteger b = new BigInteger("8806715679");//BigInteger.valueOf(233);
//		RhoResult sl = new RhoResult(false, BigInteger.ONE);
//		do{
//			b = b.divide(sl.factor);
//			sl = PollardMethod(b,BigInteger.valueOf(3));
//			System.out.println(sl.toString());
//			System.out.println(isPrime(sl.factor));
//		}while(b != sl.factor);
//		remoteSupport  = remote().start("localhost", 2553); 
//        ActorRef client = remote().actorFor(MasterAndWorker.class.getName(), 
//                      "localhost", 2553); 
//        RhoRequest req = new RhoRequest(new BigInteger("9398726230209357241"), new BigInteger("10"));
//        client.tell(req); 
	} 

}
